package com.yonyou.ucf.mdf.app.extend.event.eeac.impl;

import com.yonyou.iuap.context.InvocationInfoProxy;
import com.yonyou.iuap.metadata.api.itf.MetadataSupportService;
import com.yonyou.iuap.metadata.api.model.base.IAttribute;
import com.yonyou.iuap.metadata.api.model.base.IEntity;
import com.yonyou.iuap.ucf.common.i18n.InternationalUtils;
import com.yonyou.uap.billcode.BillCodeField;
import com.yonyou.uap.billcode.StaticVar;
import com.yonyou.ucf.mdf.app.extend.event.eeac.api.YpdFieeacEventExecuteService;
import com.yonyou.ucf.mdf.app.extend.event.eeac.constant.ExtBillCommonConstant;
import com.yonyou.ucf.mdf.app.extend.event.eeac.dto.FieeacEventDTO;
import com.yonyou.ucf.transtype.model.BdBillType;
import com.yonyou.ucf.transtype.service.itf.IBillTypeService;
import com.yonyou.ypd.bill.basic.BillActionInfo;
import com.yonyou.ypd.bill.basic.constant.BillActionEnum;
import com.yonyou.ypd.bill.basic.constant.DOStatusEnum;
import com.yonyou.ypd.bill.basic.entity.BillDOUtils;
import com.yonyou.ypd.bill.basic.entity.IBillDO;
import com.yonyou.ypd.bill.basic.entity.SuperDO;
import com.yonyou.ypd.bill.basic.entity.WeakTypingDO;
import com.yonyou.ypd.bill.basic.exception.YpdException;
import com.yonyou.ypd.bill.basic.json.JsonUtils;
import com.yonyou.ypd.bill.context.YpdBillContext;
import com.yonyou.ypd.bill.infrastructure.service.api.IBillQueryRepository;
import com.yonyou.ypd.bill.infrastructure.service.api.IBillRepository;
import com.yonyou.ypd.bill.infrastructure.service.api.IEnvService;
import com.yonyou.ypd.bill.utils.IrisRpcUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * auther:gpg
 * Date:2023/11/715
 * Description: 查询单据是否可以发送事件
 */
@Service
public class YpdFieeacEventExecuteServiceImpl implements YpdFieeacEventExecuteService {

    @Autowired
    private IBillQueryRepository billQueryRepository;

    @Autowired
    private MetadataSupportService metadataSupportService;

    @Autowired
    private IBillRepository billRepository;

    @Autowired
    private IEnvService envService;

    @Override
    public Map<String, Object> query(YpdBillContext billContext)throws Exception  {
        Map<String, Object> reslutMap = new HashMap<>();
        Boolean sendFlag = true;

        //获取action中的对接场景
        BillActionInfo actionInfo = billContext.getBaseBillContext().getActionInfo();

        //判断是否可以发送事件
        //1.当前是否能查询到单据信息
        Map<String, Object> billInfo = billQueryRepository.queryByID(billContext.getBaseBillContext().getBillEntityInfo(), billContext.getBillDO().getPrimaryKey());
        if(null == billInfo || billInfo.isEmpty()) {
            throw new YpdException("业务事项推送失败：单据已删除或者没权限!");
        }

        //pubts校验
//        Object pubts = billContext.getBillDO().getAttrValue(billContext.getBillDO().getBillField().getField_pubts());
//        if(ObjectUtils.isNotEmpty(pubts) && !pubts.equals(billInfo.get(billContext.getBillDO().getBillField().getField_pubts()))) {
//            throw new YpdException("当前单据不是最新状态，请刷新重试。");
//        }

        /**
         * 单据过账状态
         * 0：未过账
         * 1：过账中
         * 2：过账成功
         * 3：过账失败
         * 4：不过账
         */
        if(ExtBillCommonConstant.ACTIONCODE_EEACSEND.equals(actionInfo.getCode())) {//手动发送事件
            sendFlag = sendExtracted(billContext, billInfo);
        }

        if(ExtBillCommonConstant.ACTIONCODE_EEACREVERSE.equals(actionInfo.getCode())) {//手动逆向调用事件
            sendFlag = reverseExtracted(billContext, billInfo);
        }

        reslutMap.put("billInfo", billInfo);
        reslutMap.put("sendFlag", sendFlag);
        return reslutMap;
    }

    @Override
    public Boolean sendFlag(YpdBillContext billContext) throws Exception {
        Boolean sendFlag = true;

        //获取action中的对接场景
        BillActionInfo actionInfo = billContext.getBaseBillContext().getActionInfo();

        /**
         * 单据过账状态
         * 0：未过账
         * 1：过账中
         * 2：过账成功
         * 3：过账失败
         * 4：不过账
         */
        if(BillActionEnum.ACTIONCODE_DELETE.equals(actionInfo.getCode())) {//删除单据
            sendFlag = deleteExtracted(billContext);
        }


        return sendFlag;
    }

    @Override
    public void updateStatus(IBillDO billDO, Long dataVersion, String status) throws Exception {
        //更新单据状态
        String userId = InvocationInfoProxy.getUserid();
        Date now = BillDOUtils.getNowDate();
        billDO.setAttrValue(billDO.getBillField().getField_modifier(), userId);//修改人
        billDO.setAttrValue(billDO.getBillField().getField_modifyTime(), now);//修改time
        billDO.setAttrValue(ExtBillCommonConstant.FIELD_EEACVERSION, dataVersion);//数据版本
        billDO.setAttrValue(ExtBillCommonConstant.FIELD_EEACSTATUS, status);//过账状态
        String[] changedPropertyNames = new String[]{billDO.getBillField().getField_modifier(),
                billDO.getBillField().getField_modifyTime(),
                ExtBillCommonConstant.FIELD_EEACVERSION,//数据版本
                ExtBillCommonConstant.FIELD_EEACSTATUS//过账状态
        };
        if (billDO instanceof SuperDO) {
            ((SuperDO) billDO).setChangedPropertyNames(changedPropertyNames);
            ((SuperDO) billDO).set_status((int) DOStatusEnum.UPDATE);
        } else if (billDO instanceof WeakTypingDO) {
            ((WeakTypingDO) billDO).setChangedPropertyNames(changedPropertyNames);
            ((WeakTypingDO) billDO).set_status((int) DOStatusEnum.UPDATE);
        }

        billRepository.updateBillDO(billDO);
    }

    @Override
    public FieeacEventDTO convertFieeacEventDTO(YpdBillContext billContext, Long dataVersion, String eventAction) throws Exception {
        FieeacEventDTO fieeacEventDTO = new FieeacEventDTO();
        if("add".equals(eventAction)) {
            Map<String, Object> dataMap = JsonUtils.json2Pojo(JsonUtils.toJsonString(billContext.getBillDO()), Map.class);
            fieeacEventDTO.setData(dataMap);
        }
        fieeacEventDTO.setBillNo(billContext.getBaseBillContext().getcBillNo());
        fieeacEventDTO.setBusObj(billContext.getBaseBillContext().getBusiObj());
        fieeacEventDTO.setBillId(billContext.getBillDO().getPrimaryKey());
        Object orgId = billContext.getBillDO().getAttrValue(billContext.getBillDO().getBillField().getField_orgId());
        if(ObjectUtils.isNotEmpty(orgId)) {
            fieeacEventDTO.setOrgId(orgId.toString());
        }
        List<BillCodeField> primaryCodeFieldList = getCodeFieldListByEntity(metadataSupportService.getEntityByUri(billContext.getBaseBillContext().getMetaFullName()));
        if(CollectionUtils.isNotEmpty(primaryCodeFieldList)) {
            Object billCodeObj = billContext.getBillDO().getAttrValue(primaryCodeFieldList.get(0).getFieldName());
            if(ObjectUtils.isNotEmpty(billCodeObj)) {
                fieeacEventDTO.setBillCode((String) billCodeObj);
            }
        };
        fieeacEventDTO.setBillDate(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        String formId = String.format("%s.%s", envService.getAppName(), billContext.getBaseBillContext().getBusiObj());
        BdBillType bdBillType = IrisRpcUtil.getIrisReference("transtype", IBillTypeService.class).getBillTypeByFormId(InvocationInfoProxy.getTenantid(),formId);
        fieeacEventDTO.setBillTypeId(bdBillType.getId());//单据类型id
        Object bustypeObj = billContext.getBillDO().getAttrValue(billContext.getBillDO().getBillField().getField_bustype());
        if(ObjectUtils.isNotEmpty(bustypeObj)) {
            fieeacEventDTO.setTradeTypeId((String) bustypeObj);//交易类型
        }
        if("add".equals(eventAction)) {//发送事项状态
            if(ObjectUtils.isNotEmpty(dataVersion)) {
                dataVersion = dataVersion + 1L;
            } else {
                dataVersion = 1L;
            }
        }
        fieeacEventDTO.setDataVersion(dataVersion);
        fieeacEventDTO.setEntityUri(StringUtils.isNotEmpty(billContext.getBaseBillContext().getMetaFullName()) ? billContext.getBaseBillContext().getMetaFullName() : billContext.getBaseBillContext().getBillEntityInfo().getMetaFullName());
        return fieeacEventDTO;
    }


    private Boolean sendExtracted(YpdBillContext billContext, Map<String, Object> billInfo) {
        Boolean sendFlag = true;
        /**
         * 未查询到过账状态：正常发送
         * 0未过账：正常发送
         * 1过账中：报错拦截
         * 2过账成功：报错拦截
         * 3过账失败：正常发送
         * 4不过账：不发送，不报错拦截
         */
        Object eeacStatus = billInfo.get(ExtBillCommonConstant.FIELD_EEACSTATUS); //获取查询单据后的过账状态
        if(ObjectUtils.isEmpty(eeacStatus)) {
            return sendFlag;
        }
        switch (eeacStatus.toString()) {
            case "0":
                break;
            case "1":
                throw new YpdException("业务事项推送失败：过帐中");
            case "2":
                throw new YpdException("过账成功，无需再次发送");
            case "3":
                break;
            case "4":
                sendFlag = false;
        }
        return sendFlag;
    }


    private Boolean reverseExtracted(YpdBillContext billContext, Map<String, Object> billInfo) {
        Boolean sendFlag = true;
        /**
         * 未查询到过账状态：报错拦截
         * 0未过账：报错拦截
         * 1过账中：报错拦截
         * 2过账成功：正常发送
         * 3过账失败：不发送，不报错拦截
         * 4不过账：不发送，不报错拦截
         */
        Object eeacStatus = billInfo.get(ExtBillCommonConstant.FIELD_EEACSTATUS); //获取查询单据后的过账状态
        if(ObjectUtils.isEmpty(eeacStatus)) {
            throw new YpdException("业务事项逆向调用失败：未查询到过账状态");
        }
        switch (eeacStatus.toString()) {
            case "0":
                throw new YpdException("单据未过账，过账成功后再进行此操作");
            case "1":
                throw new YpdException("业务事项逆向调用失败：过帐中");
            case "2":
                break;
            case "3":
                sendFlag = false;
                break;
            case "4":
                sendFlag = false;
        }
        return sendFlag;
    }


    private Boolean deleteExtracted(YpdBillContext billContext) {
        Boolean sendFlag = true;
        Object eeacStatus = billContext.getBillDO().getAttrValue(ExtBillCommonConstant.FIELD_EEACSTATUS); //获取查询单据后的过账状态
        Object dataVersion = billContext.getBillDO().getAttrValue(ExtBillCommonConstant.FIELD_EEACVERSION); ;//数据版本
        if(ObjectUtils.isEmpty(eeacStatus)) {
            throw new YpdException("业务事项逆向调用失败：未获取到过账状态");
        }
        if(ObjectUtils.isEmpty(dataVersion)) {
            throw new YpdException("业务事项逆向调用失败：未获取到过账数据版本");
        }
        /**
         * 0未过账：不发送，不报错拦截
         * 1过账中：报错拦截
         * 2过账成功：发送
         * 3过账失败：不发送，不报错拦截
         * 4不过账：不发送，不报错拦截
         */
        switch (eeacStatus.toString()) {
            case "0":
                sendFlag = false;
                break;
            case "1":
                throw new YpdException("业务事项逆向调用失败：过帐中");
            case "2":
                break;
            case "3":
                sendFlag = false;
                break;
            case "4":
                sendFlag = false;
        }
        return sendFlag;
    }


    private List<BillCodeField> getCodeFieldListByEntity(IEntity entity) {
        List<BillCodeField> codeFieldList = new ArrayList<>();
        // 单据中编码字段
        IAttribute attribute = entity.getCodeAttribute();
        if (attribute == null || StringUtils.isBlank(attribute.getName())) {
            return codeFieldList;
        }

        String resId = attribute.getResId();
        String fieldTitle = attribute.getTitle();
        if (StringUtils.isNotBlank(resId)) {
            fieldTitle = InternationalUtils.getMessageWithDefault(resId, fieldTitle);
        }
        BillCodeField billNoField = new BillCodeField(attribute.getName(), StaticVar.BILLCODEFIELD_TERMCODE_ISBILLNO, fieldTitle);

        codeFieldList.add(billNoField);

        // 单据中所有字段
        List<IAttribute> attributeList = entity.getAttributes();
        for (IAttribute attributeTemp : attributeList) {
            boolean isCodeField = attributeTemp.containsTerm(StaticVar.BILLCODEFIELD_TERMCODE_ISCODEFIELD);
            if (!isCodeField) {
                continue;
            }
            if (StringUtils.isNotBlank(attributeTemp.getName())
                    && codeFieldList.stream().map(BillCodeField::getFieldName).noneMatch(name -> attributeTemp.getName().equals(name))) {
                resId = attributeTemp.getResId();
                fieldTitle = InternationalUtils.getMessageWithDefault(resId, attributeTemp.getTitle());
                billNoField = new BillCodeField(attributeTemp.getName(), StaticVar.BILLCODEFIELD_TERMCODE_ISBILLNO, fieldTitle);
                codeFieldList.add(billNoField);
            }
        }
        return codeFieldList;
    }
}
